<?php
/**
 * SellerShippingRepo.php
 *
 * @copyright  2023 beikeshop.com - All Rights Reserved
 * @link       https://beikeshop.com
 * @author     TL <mengwb@guangda.work>
 * @created    2023-05-17 15:22:05
 * @modified   2023-05-17 15:22:05
 */

namespace Beike\Seller\Repositories;

use Beike\Libraries\Weight;
use Beike\Models\ProductSku;
use Beike\Seller\Models\Product;
use Beike\Seller\Models\SellerShipping;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;

class SellerShippingRepo
{
    /**
     * 创建一个记录
     * @param $data
     * @return Builder|Model
     */
    public static function create($data): Model|Builder
    {
        $data = [
            'seller_id' => is_admin() ? 0 : current_seller_user()->seller_id,
            'region_id' => $data['region_id'],
            'type'      => $data['type'],
            'method'    => $data['method'] ?? '',
            'flat'      => $data['flat'] ?: 0,
            'rules'     => $data['rules'],
            'priority'  => (int) ($data['priority'] ?: 0),
            'status'    => $data['status'],
        ];

        return SellerShipping::query()->create($data);
    }

    /**
     * @param $id
     * @param $data
     * @return Builder|Builder[]|Collection|Model
     * @throws \Exception
     */
    public static function update($id, $data): Model|Collection|Builder|array
    {
        $sellerShipping = SellerShipping::query()->find($id);
        if (! $sellerShipping) {
            throw new \Exception("Seller Shipping id {$id} not exist");
        }
        $data = [
            'region_id' => $data['region_id'],
            'type'      => $data['type'],
            'method'    => $data['method'] ?? '',
            'flat'      => $data['flat'] ?: 0,
            'rules'     => $data['rules'],
            'priority'  => (int) ($data['priority'] ?: 0),
            'status'    => $data['status'],
        ];

        $sellerShipping->update($data);

        return $sellerShipping;
    }

    /**
     * @param $id
     * @return Builder|Builder[]|Collection|Model|null
     */
    public static function find($id): Model|Collection|Builder|array|null
    {
        return SellerShipping::query()->findOrFail($id);
    }

    /**
     * @param $id
     * @return void
     */
    public static function delete($id)
    {
        $sellerShipping = SellerShipping::query()->find($id);
        if ($sellerShipping) {
            $sellerShipping->delete();
        }
    }

    /**
     * 获取列表
     *
     * @return Builder[]|Collection
     */
    public static function list($sellerId): Collection|array
    {
        $builder = SellerShipping::query()->where('seller_id', $sellerId)->orderBy('id', 'desc');

        return $builder->get();
    }

    /**
     * @param $sellerId
     * @param $zoneId
     * @return Builder|Model|object|null
     */
    public static function getSellerShippingByZoneId($sellerId, $zoneId)
    {
        return SellerShipping::query()
            ->where('seller_id', $sellerId)
            ->where('status', true)
            ->whereHas('regionZones', function ($query) use ($zoneId) {
                $query->whereIn('zone_id', [$zoneId, 0]);
            })
            ->orderBy('priority')
            ->first();
    }

    /**
     * @param $sellerId
     * @param $shipping
     * @param $totalService
     * @return float|mixed|void
     */
    public static function getShippingFee($sellerId, $shipping, $totalService)
    {
        if (! $shipping) {
            return;
        }

        $type = $shipping->type;

        // Handle flat first
        if ($type == 'by_flat') {
            return $shipping->flat;
        }

        // Calculate unit value
        $unit = 0;
        switch ($type) {
            case 'by_weight':
                $unit = self::getCartWeight($sellerId, $totalService);

                break;
            case 'by_volume':
                $unit = self::getCartProductTotalVolumes($sellerId, $totalService);

                break;
            default:
                break;
        }

        if (! $shipping->rules) {
            return;
        }

        if ($shipping->method != 'cumulative') { // Range cost
            $rules = json_decode($shipping->rules, true);
            foreach ($rules as $index => $range) {
                $start = $range['start'];
                $end   = $range['end'];
                $cost  = $range['cost'];
                $block = $range['block'];

                if ($unit < $start || $unit > $end) { // Out of range
                    continue;
                }

                // In range
                if ($block > 0) {
                    $unit = ceil($unit / $block);
                    $cost *= $unit;
                }

                return $cost + $shipping->flat;
            }
        } else { // Cumulative cost
            $cumulatedCost = $shipping->flat;
            $cumulatedUnit = 0;

            $rules = json_decode($shipping->rules, true);
            foreach ($rules as $index => $range) {
                $start = $range['start'];
                $end   = $range['end'];
                $cost  = $range['cost'];
                $block = $range['block'];

                // 第 1 条规则，是否满足最小值？
                if ($index == 0) {
                    if ($unit < $start) {
                        return;
                    }
                }

                // Out of range
                if ($unit > $end) {
                    if ($block > 0) {
                        $blockedUnit = ceil(($end - $cumulatedUnit) / $block);
                        $cost *= $blockedUnit;
                    }
                    $cumulatedCost += $cost;
                    $cumulatedUnit = $end;

                    continue;
                }

                // In range
                if ($block > 0) {
                    $unit -= $cumulatedUnit;
                    $blockUnit = ceil($unit / $block);
                    $cost *= $blockUnit;
                }

                $cumulatedCost += $cost;

                return $cumulatedCost;
            }
        }
    }

    /**
     * @param $sellerId
     * @param $totalService
     * @return float|int
     */
    public static function getCartWeight($sellerId, $totalService)
    {
        $cartProducts = $totalService->getCartProducts()[$sellerId] ?? [];

        $weight = 0;
        foreach ($cartProducts['list'] as $cartProduct) {
            $weight += $cartProduct['weight'] * $cartProduct['quantity'];
        }

        return $weight;
    }

    /**
     * @param $sellerId
     * @param $totalService
     * @return int
     */
    public static function getCartProductTotalVolumes($sellerId, $totalService)
    {
        return 0;
    }
}
